interface Message{
	message:string,
	key:string,
	type:string,
	action?:string
}
interface Sms{
	name?: string,//名称
	api?: any,//请求接口
	queryParams?: any,//请求参数
	loading?: boolean,//发送状态
	disabled?: boolean,//禁止发送
	prompt?: string,//验证码按钮文字
	count?: number,//验证码倒计时时间
	timer?: any,//验证码倒计时定时器
	seconds?: number,//验证码倒计时时长
	status?: boolean//禁用状态
	sendMessage?: string
	successMessage?: string
	againMessage?: string
	failMessage?: string
}
interface Rule{
	name:string,//被检测对象名
	required?:boolean,//是否必填
	message?:string,//报错信息
	noneMessage?:string,//字段为空提示消息
	regExMessage?:string,//正则提示消息
	checkMessage?:string,//函数提示消息
	uniqueMessage?:string,//唯一提示消息
	trigger?:string,//触发检测input blur
	type?:string, //类型 phone email emailCn amount interger count password
	pattern?:any, //正则表达式
	max?:number,//最大值
	min?:number,//最小值
	length?:number,//长度
	maxLength?:number,//最大长度
	minLength?:number//最小长度
	action?:string//报警类名
	actionClassName?:string,//报警动作类名
	alone?:boolean,//单独校验
	unique?:boolean,//唯一校验(针对数组)
	checkFn?:Function//检验函数
	rings?:any//报警对象
	isChecked?:boolean//是否验证通过
}

export default class Form{
	static formMessages = new Map();
	static formSms = new Map();
	static messages = new Map();
	static actionClassName:string = "";//警告动作类名
	static regEx = {
		phone:{//电话号码
			test:/^(1[3-9]\d{9})$|^([69]\d{7})$|^([6]\d{5})$|^(09\d{8})$/,
			message:"请输入正确手机号"
		},
		email:{//普通邮箱
			test:/^([a-zA-Z]|[0-9])(\w|\-)+@[a-zA-Z0-9]+\.([a-zA-Z]{2,4})$/,
			message:"邮箱格式错误"
		},
		emailCn:{//中文邮箱
			test:/^[A-Za-z0-9\u4e00-\u9fa5]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$/,
			message:"邮箱格式错误"
		},
		amount:{//正金额
			test:/(^[1-9]([0-9]+)?(\.[0-9]{1,2})?$)|(^(0){1}$)|(^[0-9]\.[0-9]([0-9])?$)/,
			message:"金额格式错误"
		},
		integer:{//正整数
			test:/^(0|[1-9][0-9]*)$/,
			message:"整数格式错误"
		},
		count:{//数量
			test:/^[1-9]\d*$/,
			message:"数字格式错误"
		},
		username:{//用户名
			test:/^[a-zA-Z0-9_-]{4,16}$/,
			message:"用户名格式错误"
		},
		password:{//字母+数字
			test:/^(?![0-9]+$)(?![a-zA-Z]+$)[a-zA-Z0-9]{6,10}$/,
			message:"密码格式错误"
		},
		passwordMiddle:{//中：字母+数字，字母+特殊字符，数字+特殊字符
			test:/^(?![a-zA-z]+$)(?!\d+$)(?![!@#$%^&*]+$)[a-zA-Z\d!@#$%^&*]+$/,
			message:"密码格式错误"
		},
		passwordHigh:{//字母+数字+特殊字符
			test:/^(?![a-zA-z]+$)(?!\d+$)(?![!@#$%^&*]+$)(?![a-zA-z\d]+$)(?![a-zA-z!@#$%^&*]+$)(?![\d!@#$%^&*]+$)[a-zA-Z\d!@#$%^&*]+$/,
			message:"密码格式错误"
		},
		identityCrad:{//身份证
			test:/^[1-9]\d{7}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}$|^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}([0-9]|X)$/,
			message:"身份证格式错误"
		},
		date:{//日期
			test:/^(?:(?!0000)[0-9]{4}-(?:(?:0[1-9]|1[0-2])-(?:0[1-9]|1[0-9]|2[0-8])|(?:0[13-9]|1[0-2])-(?:29|30)|(?:0[13578]|1[02])-31)|(?:[0-9]{2}(?:0[48]|[2468][048]|[13579][26])|(?:0[48]|[2468][048]|[13579][26])00)-02-29)$/,
			message:"日期格式错误"
		},
		plate:{//车牌
			test:/^[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领A-Z]{1}[A-Z]{1}[A-Z0-9]{4}[A-Z0-9挂学警港澳]{1}$/,
			message:"车牌格式错误"
		},
		url:{//http*://*.*.*?*=*(&*=*)* 如https://www.baidu.com?key=value&key=value&key=value
			test:/^(?=^.{3,255}$)(http(s)?:\/\/)?(www\.)?[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(\.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+(:\d+)*(\/\w+\.\w+)*([\?&]\w+=\w*)*$/,
			message:"链接格式错误"
		},
	}
	
	/*
	*检测对象
	* param		checkBody	被检测对象
	* param		rules  		检测规则
	* param		name	   	实体名
	* return	boolean
	*/
	public static check = (checkBody:any,rules:any,name?:string):boolean=>{
		let routes:any = getCurrentPages();
		name = routes[routes.length - 1].route + ":" + (name || 'index');
		let messages = Form.formMessages.has(name) ? Form.formMessages.get(name) : [];
		messages = [];
		for(let key in rules){
			const rule:Rule = rules[key];
			rule.isChecked = true;
			rule.action = "";
			rule.message = "";
			//必填校验
			if(rule.required){
				if(checkBody[key] === null || checkBody[key] === undefined || checkBody[key].length === 0){
					messages.unshift({message:rule.noneMessage || (rule.name + "不能为空"),type:"danger",key,name:rule.name})
					rule.isChecked = false;
				}
				//单独校验
				if(rule.alone && !rule.isChecked)break;
			}
			//正则校验
			if(rule.type && rule.isChecked){
				if(rule.pattern && rule.pattern.test(checkBody[key]) || Form.regEx[rule.type] && !Form.regEx[rule.type].test.test(checkBody[key])){
					messages.unshift({message:rule.regExMessage || Form.regEx[rule.type].message,type:"danger",key,name:rule.name})
					rule.isChecked = false;
				}
			}
			//长度检验
			if((rule.length || rule.maxLength || rule.minLength) && rule.isChecked){
				let str = checkBody[key] + "";
				if(rule.length && str.length !== rule.length){
					messages.unshift({message:rule.name + "长度至少" + rule.length + "位",type:"danger",key,name:rule.name})
					rule.isChecked = false;
				}
				if(rule.minLength && str.length < rule.minLength && rule.isChecked){
					messages.unshift({message:rule.name + "长度至少" + rule.minLength + "位",type:"danger",key,name:rule.name})
					rule.isChecked = false;
				}
				if(rule.maxLength && str.length > rule.maxLength && rule.isChecked){
					messages.unshift({message:rule.name + "长度至多" + rule.maxLength + "位",type:"danger",key,name:rule.name})
					rule.isChecked = false;
				}
			}
			//数字大小校验
			if((rule.max != undefined || rule.min != undefined) && rule.isChecked){
				let number = Number(checkBody[key]);
				if(!isNaN(number) && rule.min != undefined && number < rule.min){
					messages.unshift({message:rule.name + "不能小于" + rule.min,type:"danger",key,name:rule.name})
					rule.isChecked = false;
				}
				if(!isNaN(number) && rule.max != undefined && number > rule.max){
					messages.unshift({message:rule.name + "不能大于" + rule.max,type:"danger",key,name:rule.name})
					rule.isChecked = false;
				}
			}
			//方法检测
			if(rule.checkFn && !rule.checkFn()){
				messages.unshift({message:rule.checkMessage || (rule.message || "数据错误"),type:"danger",key,name:rule.name})
				rule.isChecked = false;
			}
			//单独校验
			if(rule.alone && !rule.isChecked)break;
		}
		//报警
		if(messages.length > 0){
			setTimeout(()=>{
				messages.forEach((item:Message) =>{
					rules[item.key].action = rules[item.key].actionClassName || Form.actionClassName;
					rules[item.key].message = item.message;
				})
			},20)
			console.log(rules)
			uni.vibrateShort();
		}
		Form.messages.set(name,messages.map((item:Message)=>item.key));
		Form.formMessages.set(name,messages);
		return messages.length == 0;
	}
	
	/*
	*检测数组对象
	* param		checkBody	被检测对象
	* param		rules  		检测规则
	* param		name	   	实体名
	* return	boolean
	*/
	public static checkArray = (checkBody:Rule[],rules:any,name?:string):boolean=>{
		let routes:any = getCurrentPages();
		name = routes[routes.length - 1].route + ":" + (name || 'index');
		let messages = Form.formMessages.has(name) ? Form.formMessages.get(name) : [];
		messages = [];
		for(let key in rules){
			const rule:Rule = rules[key];
			rule.isChecked = true;
			for(let index in checkBody){
				const checkItem = checkBody[index][key];
				checkBody[index].action = "";
				checkBody[index].message = "";
				checkBody[index].rings[key] = {action:"",message:""};
				//必填校验
				if(rule.required){
					if(checkItem == null || checkItem == undefined || checkItem.length == 0){
						messages.unshift({message:`${rule.noneMessage || (rule.name + "不能为空")}`,type:"danger",key,index,name:rule.name})
						rule.isChecked = false;
					}
					//单独校验
					if(rule.alone && !rule.isChecked)break;
				}
				//正则校验
				if(rule.type && rule.isChecked){
					if(rule.pattern && rule.pattern.test(checkItem) || Form.regEx[rule.type] && !Form.regEx[rule.type].test.test(checkItem)){
						messages.unshift({message:rule.regExMessage || Form.regEx[rule.type].message,type:"danger",key,index,name:rule.name})
						rule.isChecked = false;
					}
				}
				//长度检验
				if((rule.length || rule.maxLength || rule.minLength) && rule.isChecked){
					let str = checkItem + "";
					if(rule.length && str.length !== rule.length){
						messages.unshift({message:rule.name + "长度至少" + rule.length + "位",type:"danger",key,index,name:rule.name})
						rule.isChecked = false;
					}
					if(rule.minLength && str.length < rule.minLength && rule.isChecked){
						messages.unshift({message:rule.name + "长度至少" + rule.minLength + "位",type:"danger",key,index,name:rule.name})
						rule.isChecked = false;
					}
					if(rule.maxLength && str.length > rule.maxLength && rule.isChecked){
						messages.unshift({message:rule.name + "长度至多" + rule.maxLength + "位",type:"danger",key,index,name:rule.name})
						rule.isChecked = false;
					}
				}
				//数字大小校验
				if((rule.max != undefined || rule.min != undefined) && rule.isChecked){
					let number = Number(checkItem);
					if(!isNaN(number) && rule.min != undefined && number < rule.min){
						messages.unshift({message:rule.name + "不能小于" + rule.min,type:"danger",key,index,name:rule.name})
						rule.isChecked = false;
					}
					if(!isNaN(number) && rule.max != undefined && number > rule.max){
						messages.unshift({message:rule.name + "不能大于" + rule.max,type:"danger",key,index,name:rule.name})
						rule.isChecked = false;
					}
				}
				//方法检测
				if(rule.checkFn && !rule.checkFn()){
					messages.unshift({message:rule.checkMessage || (rule.message || "数据错误"),type:"danger",key,index,name:rule.name})
					rule.isChecked = false;
				}
				
				//唯一检测
				if(rule.unique && rule.isChecked){
					if(checkBody.filter((item,uniqueIndex) => item[key] == checkItem && uniqueIndex != Number(index)).length > 0){
						messages.unshift({message:rule.uniqueMessage || "数据不能重复",type:"danger",key,index,name:rule.name})
						rule.isChecked = false;
					}
				}
				
				if(!rule.isChecked){
					setTimeout(()=>{
						checkBody[index].rings.action = rule.actionClassName || Form.actionClassName;
						checkBody[index].rings.message = "数据不全";
						const message = messages.filter((item:any) =>{
							return item.key == key && index == item.index
						})
						if(message.length > 0){
							checkBody[index].rings[key].action = rule.actionClassName || Form.actionClassName;
							checkBody[index].rings[key].message = message[0].message
						}
					},20)
				}
				//单独校验
				if(rule.alone && !rule.isChecked)break;
			}
		}
		Form.messages.set(name,messages.map((item:Message)=>item.key));
		Form.formMessages.set(name,messages);
		return messages.length === 0;
	}
	
	/*
	*检测对象
	* param		checkBody	被检测对象
	* param		rules  		检测规则
	* param		keys	   	对象名
	* return	boolean
	*/
	public static checkItems = (json:{
		data:any,
		rules:any,
		keys?:string[],
		name?:string
	}):boolean=>{
		let routes:any = getCurrentPages();
		const name = routes[routes.length - 1].route + ":" + (json.name || 'index');
		let messages = Form.formMessages.has(name) ? Form.formMessages.get(name) : [];
		messages = [];
		for(let key in json.rules){
			if(json.keys && json.keys.indexOf(key) > -1){
				const rule:Rule = json.rules[key];
				rule.isChecked = true;
				rule.action = "";
				rule.message = "";
				//必填校验
				if(rule.required){
					if(json.data[key] === null || json.data[key] === undefined || json.data[key].length === 0){
						messages.unshift({message:rule.noneMessage || (rule.name + "不能为空"),type:"danger",key,name:rule.name})
						rule.isChecked = false;
					}
					//单独校验
					if(rule.alone && !rule.isChecked)break;
				}
				//正则校验
				if(rule.type && rule.isChecked){
					if(rule.pattern && rule.pattern.test(json.data[key]) || Form.regEx[rule.type] && !Form.regEx[rule.type].test.test(json.data[key])){
						messages.unshift({message:rule.regExMessage || Form.regEx[rule.type].message,type:"danger",key,name:rule.name})
						rule.isChecked = false;
					}
				}
				//长度检验
				if((rule.length || rule.maxLength || rule.minLength) && rule.isChecked){
					let str = json.data[key] + "";
					if(rule.length && str.length !== rule.length){
						messages.unshift({message:rule.name + "长度至少" + rule.length + "位",type:"danger",key,name:rule.name})
						rule.isChecked = false;
					}
					if(rule.minLength && str.length < rule.minLength && rule.isChecked){
						messages.unshift({message:rule.name + "长度至少" + rule.minLength + "位",type:"danger",key,name:rule.name})
						rule.isChecked = false;
					}
					if(rule.maxLength && str.length > rule.maxLength && rule.isChecked){
						messages.unshift({message:rule.name + "长度至多" + rule.maxLength + "位",type:"danger",key,name:rule.name})
						rule.isChecked = false;
					}
				}
				//数字大小校验
				if((rule.max != undefined || rule.min != undefined) && rule.isChecked){
					let number = Number(json.data[key]);
					if(!isNaN(number) && rule.min != undefined && number < rule.min){
						messages.unshift({message:rule.name + "不能小于" + rule.min,type:"danger",key,name:rule.name})
						rule.isChecked = false;
					}
					if(!isNaN(number) && rule.max != undefined && number > rule.max){
						messages.unshift({message:rule.name + "不能大于" + rule.max,type:"danger",key,name:rule.name})
						rule.isChecked = false;
					}
				}
				//方法检测
				if(rule.checkFn && !rule.checkFn()){
					messages.unshift({message:rule.checkMessage || (rule.message || "数据错误"),type:"danger",key,name:rule.name})
					rule.isChecked = false;
				}
				//单独校验
				if(rule.alone && !rule.isChecked)break;
			}
		}
		//报警
		if(messages.length > 0){
			setTimeout(()=>{
				messages.forEach((item:any):void =>{
					json.rules[item.key].action = json.rules[item.key].actionClassName || Form.actionClassName;
					json.rules[item.key].message = item.message;
				})
			},20)
			uni.vibrateShort();
		}
		Form.messages.set(name,messages.map((item:Message)=>item.key));
		Form.formMessages.set(name,messages);
		return messages.length == 0;
	}
	
	/*
	* 获取消息实体
	* param		name  		实体名
	* return 	messages	消息集合
	*/
	public static getMessages = (name?:any):Message=>{
		let routes:any = getCurrentPages();
		name = routes[routes.length - 1].route + ":" + (name || 'index');
		const messages = Form.formMessages.has(name) ? Form.formMessages.get(name) : [];
		if(!Form.formMessages.has(name))Form.formMessages.set(name,messages);
		return messages;
	}
	
	/*
	* 判断是否存在消息
	* param		name  		实体名
	* param		key  		判断字段
	* return 	result		是否包含
	*/
	public static hasMessages = (key:string,name?:any):boolean=>{
		let routes:any = getCurrentPages();
		name = routes[routes.length - 1].route + ":" + (name || 'index');
		const messages:string[] = Form.messages.has(name) ? Form.messages.get(name) : [];
		return messages.includes(key);
	}
	
	/*
	* 发送消息
	* param		api  		发送消息的请求方法	null
	* param		disabled	是否禁用				undefined
	* param		seconds		倒计时总长			60	
	* param		name		实体名				""
	* return 	sms			消息集合
	*/
	public static getSms = (sms:{
		api: Function
		queryParams?: Object
		disabled:boolean
		seconds?:number
		name?:string
		prompt?: string
		sendMessage?: string
		successMessage?: string
		againMessage?: string
		failMessage?: string
	}):Sms=>{
		let routes:any = getCurrentPages();
		const name = routes[routes.length - 1].route + ":" + (sms.name || "");
		const newSms = {
			api: null,//请求链接
			loading: false,//发送状态
			disabled: false,//禁止发送
			prompt: "获取验证码",//验证码按钮文字
			count: 61,//验证码倒计时时间
			timer: null,//验证码倒计时定时器
			seconds: 60,//验证码倒计时时长
			status: false,//警用状态
			sendMessage: "发送中...",
			successMessage: "验证码发送成功",
			againMessage: "重新发送",
			failMessage: "发送失败"
		}
		if(!Form.formSms.has(name)){
			for(let key in sms){
				newSms[key] = sms[key];
			}
			if(sms.seconds)sms.count = Number(sms.seconds) + 1;
			Form.formSms.set(name,newSms);
			return newSms;
		}else{
			return Form.formSms.get(name);
		}
	}
	
	/*
	*发送短信消息
	*param		sms  	实体
	*return
	*/
	public static sendSmsCode = (sms:Sms):any=>{
		return new Promise((resolve:any, reject:any):any=>{
			let routes:any = getCurrentPages();
			const name = routes[routes.length - 1].route + ":" + (sms.name || 'index');
			if(Form.formSms.has(name)){
				if((!sms.loading || !sms.status || !sms.disabled) && sms.count > sms.seconds){
					sms.loading = true;
					sms.status = true;
					sms.prompt = sms.sendMessage;
					Form.formSms.set(name,sms);
					sms.api && sms.api(sms.queryParams).then(():void=>{
						resolve({message:sms.successMessage,type:"success"});
						sms.count -= 1;
						sms.loading = false;
						sms.prompt = sms.count + "s";
						if(sms.timer){
							clearInterval(sms.timer);
							sms.timer = null;
						}
						Form.formSms.set(name,sms);
						sms.timer = setInterval(()=>{
							sms.count -= 1;
							sms.prompt = (sms.count < 10 ? "0" + sms.count : sms.count) + "s";
							if(sms.count == -1){
								sms.count = Number(sms.seconds) + 1;
								sms.prompt = sms.againMessage;
								sms.status = false;
								if(sms.timer){
									clearInterval(sms.timer);
									sms.timer = null;
									Form.formSms.delete(name);
								}
							}
							Form.formSms.set(name,sms);
						},1000)
						
						console.log("sms",sms)
					}).catch(():void=>{
						sms.loading = false;
						sms.status = false;
						sms.prompt = sms.failMessage;
						resolve({message: sms.failMessage,type:"danger"});
					})
				}
			}else{
				reject();
			}
		})
	}
	
	/*
	*数据提交
	* param		api  		请求方法
	* param		upJson		提交参数
	* param		name		请求名
	* param		asyn		异步
	*/
	public static submit = ({api,upJson,name}:{api:Function,upJson:any,name:string,}):any=>{
		let routes:any = getCurrentPages();
		name = routes[routes.length - 1].route + ":" + (name || '');
		return new Promise((resolve:any,reject:any)=>{
			const request = api(upJson).then((result:any):void=>{
				resolve(result)
			}).catce((err:any):void=>{
				reject(err);
			})
		})
	}
	
	/*
	*正则校验
	* param		str  		检验字符串
	* param		regExName	正则名称
	*/
	public static checkRegEx = (str:string,regExName:string):boolean =>{
		return Form.regEx[regExName].test.test(str);
	}
	
	public static resetForm = (form: any, newFrom?: Object):void =>{
		newFrom = newFrom || {}
		for(let key in form){
			form[key] = newFrom[key];
		}
	}
}